package com.mdxl.shiro.config;

import com.mdxl.shiro.entity.SysPermission;
import com.mdxl.shiro.entity.SysRole;
import com.mdxl.shiro.entity.User;
import com.mdxl.shiro.service.UserService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

public class ShiroRealm extends AuthorizingRealm {

    @Autowired
    UserService userService;

    /**
     * 权限认证，包括角色以及权限
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        // 1、如果身份认证的时候没有传入User对象，这里只能取到userName，也就是SimpleAuthenticationInfo构造的时候第一个参数传递需要User对象
        User user  = (User)principalCollection.getPrimaryPrincipal();
        // 2、身份认证通过，user已存在，接下来则获取该用户的角色以及权限
        List<SysRole> roles = userService.getUserRoleList(user.getId());

        // 3、给用户添加权限以及角色
        for (SysRole role: roles){
            // 3.1、遍历角色，给登陆的用户添加角色，以便使用该@RequiresRoles()注解
            authorizationInfo.addRole(role.getRoleName());

            // 3.2、获取该角色权限，给角色添加对应的权限，以便使用@RequiresPermissions()注解
            List<SysPermission> permissions = userService.getPermissionList(role.getId());
            for (SysPermission p : permissions){
                authorizationInfo.addStringPermission(p.getPermission());
            }
        }
        return authorizationInfo;
    }

    /**
     * 身份认证的，也就是说验证用户输入的账号和密码是否正确
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //获取用户的输入的账号
        String userName = (String)token.getPrincipal();
        //实际项目中，这里可以根据实际情况做缓存，如果不做，Shiro自己也是有时间间隔机制，2分钟内不会重复执行该方法
        User user = userService.findByUserName(userName);
        if(user == null){
            return null;
        }
        String uid  = user.getPassword();
        String salt = user.getSalt();

        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, uid, ByteSource.Util.bytes(salt),getName());

        return info;
    }
}
